package com.wb.utils

import com.fasterxml.jackson.databind.ObjectMapper
import com.wb.component.Slf4j.Companion.log
import com.gargoylesoftware.htmlunit.*
import com.gargoylesoftware.htmlunit.html.HtmlPage
import com.gargoylesoftware.htmlunit.javascript.AbstractJavaScriptEngine
import com.google.gson.Gson
import org.apache.http.HttpResponse
import org.apache.http.HttpVersion
import org.apache.http.NameValuePair
import org.apache.http.client.entity.UrlEncodedFormEntity
import org.apache.http.client.methods.HttpGet
import org.apache.http.client.methods.HttpPost
import org.apache.http.client.utils.URIBuilder
import org.apache.http.conn.ssl.SSLConnectionSocketFactory
import org.apache.http.impl.client.HttpClientBuilder
import org.apache.http.impl.client.HttpClients
import org.apache.http.message.BasicNameValuePair
import org.apache.http.protocol.HTTP
import org.apache.http.ssl.SSLContexts
import org.apache.http.util.EntityUtils
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.springframework.http.*
import org.springframework.http.HttpMethod
import org.springframework.http.converter.HttpMessageConverter
import org.springframework.http.converter.StringHttpMessageConverter
import org.springframework.util.LinkedMultiValueMap
import org.springframework.util.MultiValueMap
import org.springframework.web.client.RestTemplate
import java.net.URL
import java.net.http.HttpClient
import java.nio.charset.Charset
import java.util.*
import javax.script.ScriptEngineManager
import kotlin.collections.HashMap

/**
 * restTemplate 工具
 */
class RestUtil {

    companion object {

        val headerMap = hashMapOf(
            "User-Agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.30 Safari/537.36",
//            "Content-Type" to "application/x-www-form-urlencoded",
        )

        /**
         * @param url url地址
         * @param params 参数
         * @param headers 头
         * @param type 0.GET 1.POST
         * @param clazz 返回参数的封装
         */
        fun <T> send(
            url: String,
            param: HashMap<String, String>?,
            header: HashMap<String, String>?,
            type: Int,
            clazz: Class<T>
        ): ResponseEntity<T> {

            val rest = RestTemplate()

            val headers: MultiValueMap<String, String> = LinkedMultiValueMap<String, String>()

            val params: MultiValueMap<String, String> = LinkedMultiValueMap()

            if (header != null && header.isNotEmpty()) {
                header.forEach { k, v -> headers.set(k, v) }
            } else {
                headerMap.forEach { k, v -> headers.set(k, v) }
            }

            if (param != null && param.isNotEmpty()) {
                param.forEach { k, v -> params.set(k, v) }
            }

            val entity = HttpEntity<MultiValueMap<String, String>>(params, headers)

            var method = HttpMethod.GET
            when (type) {
                0 -> {
                    method = HttpMethod.GET
                }
                1 -> {
                    method = HttpMethod.POST
                }
            }

            val result = rest.exchange(url, method, entity, clazz)

//            println(result)

            return result
        }


        fun <T> sendJson(
            url: String,
            param: HashMap<String, Any>?,
            header: HashMap<String, String>?,
            clazz: Class<T>
        ): ResponseEntity<T> {

            val rest = RestTemplate()

            val headers = HttpHeaders()

            val params: HashMap<String, Any> = hashMapOf()

            if (header != null && header.isNotEmpty()) {
                header.forEach { k, v -> headers.set(k, v) }
            } else {
                headerMap.forEach { k, v -> headers.set(k, v) }
            }

            if (param != null && param.isNotEmpty()) {
                param.forEach { k, v -> params.put(k, v) }
            }

            headers.add("accept", "*/*")
            headers.contentType = MediaType.APPLICATION_JSON

            println(headers)

            val json = ObjectMapper().writeValueAsString(params)

            println(json)
            val entity = HttpEntity<String>(json, headers)

            val method = HttpMethod.POST

            val result = rest.exchange(url, method, entity, clazz)

//            println(result)

            return result
        }


        /**
         * 通过浏览器发送get
         */
        fun sendGet(url: String, params: HashMap<String, String>?): String {
            return sendGet(url, params, null)
        }

        /**
         * 通过浏览器发送get
         */
        fun sendGet(url: String, params: HashMap<String, String>?, header: HashMap<String, String>?): String {

            // 开启一个狗狗浏览器客户端对象
            val webClient = WebClient(BrowserVersion.CHROME)
            // 当JS执行出错的时候是否抛出异常
            webClient.options.isThrowExceptionOnScriptError = false
            // 当HTTP的状态非200时是否抛出异常
            webClient.options.isThrowExceptionOnFailingStatusCode = false
            webClient.options.isActiveXNative = false
            // 启用css加载
            webClient.options.isCssEnabled = false
            // 启用js加载
            webClient.options.isJavaScriptEnabled = true
            // 支持ajax加载
            webClient.ajaxController = NicelyResynchronizingAjaxController()

            header?.forEach { k, v -> webClient.addRequestHeader(k, v) }

            var urlx = ""

            if (!params.isNullOrEmpty()) {
                val string = StringBuffer();

                params.forEach { (k, v) ->
                    if (!v.isNullOrEmpty()) {
                        string.append(k + "=" + v + "&")
                    }
                }

                urlx = url + "?" + string
            } else {
                urlx = url
            }

            try {
                val page = webClient.getPage<Page>(urlx)

//                println(page)
                val result = page.webResponse.contentAsString

                page.cleanUp();

                return result
            } catch (e: Exception) {
                log.error("访问${urlx}出错", e)
            } finally {
                webClient.close()
            }
            return ""
        }


        /**
         * 通过浏览器发送get 获取网页内容
         */
        fun getPage(url: String, params: HashMap<String, String>?): Document? {

            // 开启一个狗狗浏览器客户端对象
            val webClient = WebClient(BrowserVersion.CHROME)
            // 当JS执行出错的时候是否抛出异常
            webClient.options.isThrowExceptionOnScriptError = false
            // 当HTTP的状态非200时是否抛出异常
            webClient.options.isThrowExceptionOnFailingStatusCode = false
            webClient.options.isActiveXNative = false
            // 启用css加载
            webClient.options.isCssEnabled = false
            // 启用js加载
            webClient.options.isJavaScriptEnabled = true
            // 支持ajax加载
            webClient.ajaxController = NicelyResynchronizingAjaxController()

            var urlx = ""

            if (!params.isNullOrEmpty()) {
                val string = StringBuffer();

                params.forEach { (k, v) ->
                    if (!v.isNullOrEmpty()) {
                        string.append(k + "=" + v + "&")
                    }
                }

                urlx = url + "?" + string
            } else {
                urlx = url
            }

            try {
                val page = webClient.getPage<HtmlPage>(urlx)

                val document = Jsoup.parse(page.asXml())

                page.cleanUp();

                return document
            } catch (e: Exception) {
                log.error("访问${urlx}出错", e)
            } finally {
                webClient.close()
            }

            return null
        }

        fun postPage(url: String, params: HashMap<String, String>?): Document? {

            // 开启一个狗狗浏览器客户端对象
            val webClient = WebClient(BrowserVersion.CHROME)
            val request = WebRequest(URL(url), com.gargoylesoftware.htmlunit.HttpMethod.POST)
            // 当JS执行出错的时候是否抛出异常
            webClient.options.isThrowExceptionOnScriptError = false
            // 当HTTP的状态非200时是否抛出异常
            webClient.options.isThrowExceptionOnFailingStatusCode = false
            webClient.options.isActiveXNative = false
            // 启用css加载
            webClient.options.isCssEnabled = false
            // 启用js加载
            webClient.options.isJavaScriptEnabled = true
            // 支持ajax加载
            webClient.ajaxController = NicelyResynchronizingAjaxController()

            request.requestParameters = arrayListOf()
            if (!params.isNullOrEmpty()) {
                params.forEach { (k, v) ->
                    if (!v.isEmpty()) {
                        request.requestParameters.add(com.gargoylesoftware.htmlunit.util.NameValuePair(k, v))
                    }
                }
            }

            try {
                val page = webClient.getPage<HtmlPage>(request)

                val document = Jsoup.parse(page.asXml())

                page.cleanUp();

                return document
            } catch (e: Exception) {
                log.error("访问${url}出错", e)
            } finally {
                webClient.close()
            }
            return null
        }

        fun httClient(
            url: String,
            type: Int,
            params: HashMap<String, String>?,
            header: HashMap<String, String>?
        ): String? {

            val http = HttpClientBuilder.create().build()

            val paramList = arrayListOf<NameValuePair>()

            if (!params.isNullOrEmpty()) {
                val string = StringBuffer();

                params.forEach { (k, v) ->
                    if (!v.isEmpty()) {
                        paramList.add(BasicNameValuePair(k, v))
                    }
                }
            }

            var res: HttpResponse? = null

            when (type) {
                0 -> {
                    val uriBuilder = URIBuilder(url)
                    uriBuilder.setParameters(paramList)
                    val get = HttpGet(uriBuilder.build())

                    res = http.execute(get)

                    get.releaseConnection()
                }
                1 -> {
                    val post = HttpPost(url)

                    post.entity = UrlEncodedFormEntity(paramList, Charset.defaultCharset())
                    res = http.execute(post)
                    post.releaseConnection()
                }
                else -> {
                }
            }

            if (res != null) {
                val result: String = EntityUtils.toString(res.getEntity())
                http.close()
                return result
            }

            return null
        }


        fun getInstance(charset: String?): RestTemplate {
            val restTemplate = RestTemplate()
            val list: List<HttpMessageConverter<*>> = restTemplate.messageConverters
            for (httpMessageConverter in list) {
                if (httpMessageConverter is StringHttpMessageConverter) {
                    (httpMessageConverter as StringHttpMessageConverter).setDefaultCharset(Charset.forName(charset))
                    break
                }
            }
            return restTemplate
        }

    }

}

fun main() {
    RestUtil.send("http://dyxs12.com/paly-195979-1-1/", null, null, 0, String::class.java)
}
